package com.revolsys.doclet; import java.io.File; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import javax.xml.namespace.QName; import org.springframework.util.StringUtils; import com.revolsys.io.FileUtil; import com.revolsys.record.io.format.xml.XmlWriter; import com.revolsys.util.HtmlAttr; import com.revolsys.util.HtmlElem; import com.revolsys.util.HtmlUtil; import com.revolsys.util.Property; import com.sun.javadoc.AnnotationDesc; import com.sun.javadoc.AnnotationTypeDoc; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.Doc; import com.sun.javadoc.DocErrorReporter; import com.sun.javadoc.ExecutableMemberDoc; import com.sun.javadoc.MemberDoc; import com.sun.javadoc.MethodDoc; import com.sun.javadoc.PackageDoc; import com.sun.javadoc.ParamTag; import com.sun.javadoc.ParameterizedType; import com.sun.javadoc.ProgramElementDoc; import com.sun.javadoc.SeeTag; import com.sun.javadoc.Tag; import com.sun.javadoc.Type; import com.sun.javadoc.WildcardType; public class DocletUtil { private static final Map<String, String> PACKAGE_URLS = new LinkedHashMap<>(); static { addPackageUrl("java.", "http://docs.oracle.com/javase/8/docs/api/"); addPackageUrl("com.revolsys.jts.", "http://tsusiatsoftware.net/jts/javadoc/"); } public static void addPackageUrl(final String packagePrefix, final String url) { PACKAGE_URLS.put(packagePrefix, url); } public static void anchor(final XmlWriter writer, final String name, final String title) { writer.startTag(HtmlElem.A); writer.attribute(HtmlAttr.NAME, name); writer.text(title); writer.endTag(HtmlElem.A); } public static void contentContainer(final XmlWriter writer, final String firstColClass) { writer.startTag(HtmlElem.DIV); writer.attribute(HtmlAttr.CLASS, "container-fluid"); writer.startTag(HtmlElem.DIV); writer.attribute(HtmlAttr.CLASS, "row"); writer.startTag(HtmlElem.DIV); writer.attribute(HtmlAttr.CLASS, firstColClass); } public static void copyFiles(final String destDir) { for (final String name : Arrays.asList("bootstrap-custom.css", "javadoc.css", "javadoc.js", "javadoc.js")) { FileUtil.copy(DocletUtil.class.getResourceAsStream("/com/revolsys/doclet/" + name), new File(destDir, name)); } } public static String description(final ClassDoc containingClass, final Tag doc) { final Tag[] tags = doc.inlineTags(); return description(containingClass, tags); } public static String description(final ClassDoc containingClass, final Tag[] tags) { final StringBuilder text = new StringBuilder(); if (tags != null && tags.length > 0) { for (final Tag tag : tags) { final String kind = tag.kind(); if (tag instanceof SeeTag) { final SeeTag seeTag = (SeeTag)tag; seeTag(text, containingClass, seeTag); } else if ("Text".equals(kind)) { text.append(tag.text()); } } } return text.toString(); } public static void description(final XmlWriter writer, final ClassDoc containingClass, final Doc doc) { final Tag[] tags = doc.inlineTags(); description(writer, containingClass, tags); } public static void description(final XmlWriter writer, final ClassDoc containingClass, final Tag[] tags) { if (tags != null && tags.length > 0) { for (final Tag tag : tags) { final String kind = tag.kind(); if (tag instanceof SeeTag) { final SeeTag seeTag = (SeeTag)tag; seeTag(writer, containingClass, seeTag); } else if ("Text".equals(kind)) { writer.write(tag.text()); } } } } public static void descriptionTd(final XmlWriter writer, final ClassDoc containingClass, final Map<String, Tag[]> descriptions, final String name) { writer.startTag(HtmlElem.TD); writer.attribute(HtmlAttr.CLASS, "description"); final Tag[] description = descriptions.get(name); description(writer, containingClass, description); writer.endTagLn(HtmlElem.TD); } public static void documentationReturn(final XmlWriter writer, final MethodDoc method) { final Type type = method.returnType(); if (type != null && !"void".equals(type.qualifiedTypeName())) { Tag[] descriptionTags = null; for (final Tag tag : method.tags()) { if (tag.name().equals("@return")) { descriptionTags = tag.inlineTags(); } } writer.startTag(HtmlElem.DIV); writer.startTag(HtmlElem.STRONG); writer.text("Return"); writer.endTag(HtmlElem.STRONG); writer.endTagLn(HtmlElem.DIV); typeNameLink(writer, type); writer.text(" "); description(writer, method.containingClass(), descriptionTags); } } public static void endContentContainer(final XmlWriter writer) { writer.endTagLn(HtmlElem.DIV); writer.endTagLn(HtmlElem.DIV); writer.endTagLn(HtmlElem.DIV); } public static AnnotationDesc getAnnotation(final AnnotationDesc[] annotations, final String name) { for (final AnnotationDesc annotation : annotations) { final AnnotationTypeDoc annotationType = annotation.annotationType(); final String annotationName = qualifiedName(annotationType); if (name.equals(annotationName)) { return annotation; } } return null; } public static AnnotationDesc getAnnotation(final ProgramElementDoc doc, final String name) { final AnnotationDesc[] annotations = doc.annotations(); return getAnnotation(annotations, name); } public static String getExternalUrl(final String qualifiedTypeName) { for (final Entry<String, String> entry : PACKAGE_URLS.entrySet()) { final String packagePrefix = entry.getKey(); if (qualifiedTypeName.startsWith(packagePrefix)) { final String baseUrl = entry.getValue(); final String url = baseUrl + qualifiedTypeName.replaceAll("\\.", "/") + ".html?is-external=true"; return url; } } return null; } public static Map<String, Tag[]> getParameterDescriptions(final ExecutableMemberDoc method) { final Map<String, Tag[]> descriptions = new HashMap<>(); for (final ParamTag tag : method.paramTags()) { final String parameterName = tag.parameterName(); final Tag[] commentTags = tag.inlineTags(); descriptions.put(parameterName, commentTags); } return descriptions; } public static boolean hasAnnotation(final AnnotationDesc[] annotations, final String name) { final AnnotationDesc annotation = getAnnotation(annotations, name); return annotation != null; } public static boolean hasAnnotation(final ProgramElementDoc doc, final String name) { final AnnotationDesc annotation = getAnnotation(doc, name); return annotation != null; } public static void headOld(final XmlWriter writer, final String docTitle) { writer.startTag(HtmlElem.HEAD); writer.element(HtmlElem.TITLE, docTitle); for (final String url : Arrays.asList( "https://code.jquery.com/ui/1.11.2/themes/cupertino/jquery-ui.css", "https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.css", "https://cdn.datatables.net/1.10.6/css/jquery.dataTables.min.css", "javadoc.css")) { HtmlUtil.serializeCss(writer, url); } for (final String url : Arrays.asList("https://code.jquery.com/jquery-1.12.1.min.js", "https://code.jquery.com/ui/1.11.4/jquery-ui.min.js", "https://cdn.datatables.net/1.10.11/js/jquery.dataTables.min.js", "javadoc.js")) { HtmlUtil.serializeScriptLink(writer, url); } writer.endTagLn(HtmlElem.HEAD); } public static void htmlFoot(final XmlWriter writer) { HtmlUtil.serializeScriptLink(writer, "https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js", "https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js", "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js", "https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.js"); writer.startTag(HtmlElem.SCRIPT); writer.textLn("$(function() {"); writer.textLn(" prettyPrint();"); writer.textLn("});"); writer.endTag(HtmlElem.SCRIPT); writer.endTagLn(HtmlElem.BODY); writer.endTagLn(HtmlElem.HTML); writer.endDocument(); } public static void htmlHead(final XmlWriter writer, final String docTitle, final Collection<String> customCssUrls) { writer.docType("<!DOCTYPE html>"); writer.startTag(HtmlElem.HTML); writer.attribute(HtmlAttr.LANG, "en"); writer.newLine(); writer.startTagLn(HtmlElem.HEAD); writer.startTag(HtmlElem.META); writer.attribute(HtmlAttr.CHARSET, "utf-8"); writer.endTagLn(HtmlElem.META); writer.startTag(HtmlElem.META); writer.attribute(HtmlAttr.HTTP_EQUIV, "X-UA-Compatible"); writer.attribute(HtmlAttr.CONTENT, "IE=edge"); writer.endTagLn(HtmlElem.META); writer.startTag(HtmlElem.META); writer.attribute(HtmlAttr.NAME, "viewport"); writer.attribute(HtmlAttr.CONTENT, "width=device-width, initial-scale=1"); writer.endTagLn(HtmlElem.META); writer.elementLn(HtmlElem.TITLE, docTitle); HtmlUtil.serializeCss(writer, "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css", "https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.css", "bootstrap-custom.css"); if (Property.hasValue(customCssUrls)) { HtmlUtil.serializeCss(writer, customCssUrls); } HtmlUtil.serializeStyle(writer, "body{padding-top:60px}\n" + "*[id]:before {display:block;content:' ';margin-top:-75px;height:75px;visibility:hidden;}"); writer.endTagLn(HtmlElem.HEAD); writer.startTag(HtmlElem.BODY); writer.attribute("data-spy", "scroll"); writer.attribute("data-target", "#navMain"); writer.attribute("data-offset", "60"); writer.newLine(); } public static boolean isTypeIncluded(final Type type) { final ClassDoc classDoc = type.asClassDoc(); final ClassDoc annotationDoc = type.asAnnotationTypeDoc(); final boolean included = annotationDoc != null && annotationDoc.isIncluded() || classDoc != null && classDoc.isIncluded(); return included; } public static void label(final StringBuilder text, final String label, final boolean code) { if (code) { text.append("<code>"); } text(text, label); if (code) { text.append("</code>"); } } public static void label(final XmlWriter writer, final String label, final boolean code) { if (code) { writer.startTag(HtmlElem.CODE); } writer.text(label); if (code) { writer.endTagLn(HtmlElem.CODE); } } public static void link(final StringBuilder text, final String url, final String label, final boolean code) { final boolean hasUrl = StringUtils.hasText(url); if (hasUrl) { text.append("<a href=\""); text.append(url); text.append("\">"); } label(text, label, code); if (hasUrl) { text.append("</a>"); } } public static void link(final XmlWriter writer, final String url, final String label, final boolean code) { final boolean hasUrl = StringUtils.hasText(url); if (hasUrl) { writer.startTag(HtmlElem.A); writer.attribute(HtmlAttr.HREF, url); } label(writer, label, code); if (hasUrl) { writer.endTag(HtmlElem.A); } } public static void navbarEnd(final XmlWriter writer) { writer.endTagLn(HtmlElem.UL); writer.endTagLn(HtmlElem.DIV); writer.endTagLn(HtmlElem.DIV); writer.endTagLn(HtmlElem.NAV); } public static void navbarStart(final XmlWriter writer, final String title) { writer.startTag(HtmlElem.NAV); writer.attribute(HtmlAttr.ID, "navMain"); writer.attribute(HtmlAttr.CLASS, "navbar navbar-default navbar-fixed-top"); writer.newLine(); writer.startTag(HtmlElem.DIV); writer.attribute(HtmlAttr.CLASS, "container"); writer.newLine(); { writer.startTag(HtmlElem.DIV); writer.attribute(HtmlAttr.CLASS, "navbar-header"); writer.newLine(); { writer.startTag(HtmlElem.BUTTON); writer.attribute(HtmlAttr.TYPE, "button"); writer.attribute(HtmlAttr.CLASS, "navbar-toggle collapsed"); writer.attribute("data-toggle", "collapse"); writer.attribute("data-target", "#navbar"); writer.attribute("aria-expanded", "false"); writer.attribute("aria-controls", "navbar"); writer.newLine(); HtmlUtil.serializeSpan(writer, "sr-only", "Toggle navigation"); for (int i = 0; i < 3; i++) { writer.startTag(HtmlElem.SPAN); writer.attribute(HtmlAttr.CLASS, "icon-bar"); writer.text(""); writer.endTag(HtmlElem.SPAN); } writer.endTagLn(HtmlElem.BUTTON); } { writer.startTag(HtmlElem.DIV); writer.attribute(HtmlAttr.CLASS, "navbar-brand"); writer.startTag(HtmlElem.A); writer.attribute(HtmlAttr.HREF, "#"); HtmlUtil.serializeSpan(writer, "navbar-brand-title", title); writer.endTag(HtmlElem.A); writer.endTag(HtmlElem.DIV); } writer.endTagLn(HtmlElem.DIV); } { writer.startTag(HtmlElem.DIV); writer.attribute(HtmlAttr.ID, "navbar"); writer.attribute(HtmlAttr.CLASS, "navbar-collapse collapse"); writer.attribute("aria-expanded", "false"); writer.newLine(); writer.startTag(HtmlElem.UL); writer.attribute(HtmlAttr.CLASS, "nav navbar-nav"); } } public static void navDropdownEnd(final XmlWriter writer) { writer.endTagLn(HtmlElem.UL); writer.endTagLn(HtmlElem.LI); } public static void navDropdownStart(final XmlWriter writer, final String title, String url, final boolean subMenu) { writer.startTag(HtmlElem.LI); if (subMenu) { writer.attribute(HtmlAttr.CLASS, "dropdown-submenu"); } else { writer.attribute(HtmlAttr.CLASS, "dropdown"); } writer.startTag(HtmlElem.A); if (url.startsWith("#")) { url = "#" + url.substring(1).replaceAll("[^a-zA-Z0-9_]", "_"); } if (subMenu) { writer.attribute(HtmlAttr.HREF, url); } else { writer.attribute(HtmlAttr.HREF, "#"); writer.attribute(HtmlAttr.CLASS, "dropdown-toggle"); writer.attribute("data-toggle", "dropdown"); writer.attribute(HtmlAttr.ROLE, "button"); writer.attribute("aria-expanded", "false"); } writer.text(title); if (!subMenu) { writer.startTag(HtmlElem.SPAN); writer.attribute(HtmlAttr.CLASS, "caret"); writer.text(""); writer.endTag(HtmlElem.SPAN); } writer.endTag(HtmlElem.A); writer.startTag(HtmlElem.UL); writer.attribute(HtmlAttr.CLASS, "dropdown-menu"); writer.attribute(HtmlAttr.ROLE, "menu"); writer.newLine(); if (!subMenu) { navMenuItem(writer, title, url); writer.startTag(HtmlElem.LI); writer.attribute(HtmlAttr.CLASS, "divider"); writer.endTagLn(HtmlElem.LI); } } public static void navMenuItem(final XmlWriter writer, final String title, String url) { writer.startTag(HtmlElem.LI); writer.startTag(HtmlElem.A); if (url.startsWith("#")) { url = "#" + url.substring(1).replaceAll("[^a-zA-Z0-9_]", "_"); } writer.attribute(HtmlAttr.HREF, url); writer.text(title); writer.endTag(HtmlElem.A); writer.endTagLn(HtmlElem.LI); } public static int optionLength(String optionName) { optionName = optionName.toLowerCase(); if (optionName.equals("-d")) { return 2; } else if (optionName.equals("-doctitle")) { return 2; } else if (optionName.equals("-customcssurl")) { return 2; } return 0; } public static void panelEnd(final XmlWriter writer) { writer.endTagLn(HtmlElem.DIV); writer.endTagLn(HtmlElem.DIV); } public static void panelStart(final XmlWriter writer, final String panelClass, final QName headerElement, final String id, final String titlePrefix, final String title, final String titleSuffix) { writer.startTag(HtmlElem.DIV); writer.attribute(HtmlAttr.CLASS, "panel " + panelClass); writer.newLine(); writer.startTag(HtmlElem.DIV); writer.attribute(HtmlAttr.CLASS, "panel-heading"); writer.newLine(); String simpleId = null; if (Property.hasValue(id)) { simpleId = id.replaceAll("[^a-zA-Z0-9_]", "_"); if (!id.equals(simpleId)) { writer.startTag(HtmlElem.A); writer.attribute(HtmlAttr.ID, id); writer.text(""); writer.endTag(HtmlElem.A); } } writer.startTag(headerElement); writer.attribute(HtmlAttr.CLASS, "panel-title"); if (Property.hasValue(id)) { writer.attribute(HtmlAttr.ID, simpleId); } if (Property.hasValue(titlePrefix)) { writer.element(HtmlElem.SMALL, titlePrefix); writer.text(" "); } writer.text(title); if (Property.hasValue(titleSuffix)) { writer.text(" "); writer.element(HtmlElem.SMALL, titleSuffix); } writer.endTagLn(headerElement); writer.endTagLn(HtmlElem.DIV); writer.startTag(HtmlElem.DIV); writer.attribute(HtmlAttr.CLASS, "panel-body"); writer.newLine(); } public static String qualifiedName(final ProgramElementDoc element) { final String packageName = element.containingPackage().name(); return packageName + "." + element.name(); } public static String replaceDocRootDir(final String text) { int i = text.indexOf("{@"); if (i < 0) { return text; } else { final String lowerText = text.toLowerCase(); i = lowerText.indexOf("{@docroot}", i); if (i < 0) { return text; } else { final StringBuffer stringbuffer = new StringBuffer(); int k = 0; do { final int j = lowerText.indexOf("{@docroot}", k); if (j < 0) { stringbuffer.append(text.substring(k)); break; } stringbuffer.append(text.substring(k, j)); k = j + 10; stringbuffer.append("./"); if ("./".length() > 0 && k < text.length() && text.charAt(k) != '/') { stringbuffer.append("/"); } } while (true); return stringbuffer.toString(); } } } public static void seeTag(final StringBuilder text, final ClassDoc containingClass, final SeeTag seeTag) { final String name = seeTag.name(); if (name.startsWith("@link") || name.equals("@see")) { final boolean code = !name.equalsIgnoreCase("@linkplain"); String label = seeTag.label(); final StringBuffer stringbuffer = new StringBuffer(); final String seeTagText = replaceDocRootDir(seeTag.text()); if (seeTagText.startsWith("<") || seeTagText.startsWith("\"")) { stringbuffer.append(seeTagText); text.append(seeTagText); } else { final ClassDoc referencedClass = seeTag.referencedClass(); final MemberDoc referencedMember = seeTag.referencedMember(); String referencedMemberName = seeTag.referencedMemberName(); if (referencedClass == null) { final PackageDoc packagedoc = seeTag.referencedPackage(); if (packagedoc != null && packagedoc.isIncluded()) { final String packageName = packagedoc.name(); if (!StringUtils.hasText(label)) { label = packageName; } link(text, "#" + packageName, label, code); } else { // TODO link to external package or class // String s9 = getCrossPackageLink(referencedClassName); // String s8; // if (s9 != null) // stringbuffer.append(getHyperLink(s9, "", s1.length() != 0 ? s1 // : s3, false)); // else if ((s8 = getCrossClassLink(referencedClassName, // referencedMemberName, s1, false, "", !plainLink)) != null) { // stringbuffer.append(s8); // } else { // configuration.getDocletSpecificMsg().warning(seeTag.position(), // "doclet.see.class_or_package_not_found", name, s2); // stringbuffer.append(s1.length() != 0 ? s1 : s3); // } } } else { String url = null; final String className = referencedClass.qualifiedName(); if (referencedClass.isIncluded()) { url = "#" + className; } else { url = getExternalUrl(className); if (!StringUtils.hasText(url)) { label = className; } } if (referencedMember != null) { if (referencedMember instanceof ExecutableMemberDoc) { if (referencedMemberName.indexOf('(') < 0) { final ExecutableMemberDoc executableDoc = (ExecutableMemberDoc)referencedMember; referencedMemberName = referencedMemberName + executableDoc.signature(); } if (StringUtils.hasText(referencedMemberName)) { label = referencedMemberName; } else { label = seeTagText; } } if (referencedClass.isIncluded()) { url += "." + referencedMemberName; } else if (StringUtils.hasText(url)) { url += "#" + referencedMemberName; } else { label = referencedMember.toString(); } } if (!StringUtils.hasText(label)) { label = referencedClass.name(); } link(text, url, label, code); } } } } public static void seeTag(final XmlWriter writer, final ClassDoc containingClass, final SeeTag seeTag) { final String name = seeTag.name(); if (name.startsWith("@link") || name.equals("@see")) { final boolean code = !name.equalsIgnoreCase("@linkplain"); String label = seeTag.label(); final StringBuffer stringbuffer = new StringBuffer(); final String seeTagText = replaceDocRootDir(seeTag.text()); if (seeTagText.startsWith("<") || seeTagText.startsWith("\"")) { stringbuffer.append(seeTagText); writer.write(seeTagText); } else { final ClassDoc referencedClass = seeTag.referencedClass(); final MemberDoc referencedMember = seeTag.referencedMember(); String referencedMemberName = seeTag.referencedMemberName(); if (referencedClass == null) { final PackageDoc packagedoc = seeTag.referencedPackage(); if (packagedoc != null && packagedoc.isIncluded()) { final String packageName = packagedoc.name(); if (!StringUtils.hasText(label)) { label = packageName; } link(writer, "#" + packageName, label, code); } else { // TODO link to external package or class // String s9 = getCrossPackageLink(referencedClassName); // String s8; // if (s9 != null) // stringbuffer.append(getHyperLink(s9, "", s1.length() != 0 ? s1 // : s3, false)); // else if ((s8 = getCrossClassLink(referencedClassName, // referencedMemberName, s1, false, "", !plainLink)) != null) { // stringbuffer.append(s8); // } else { // configuration.getDocletSpecificMsg().warning(seeTag.position(), // "doclet.see.class_or_package_not_found", name, s2); // stringbuffer.append(s1.length() != 0 ? s1 : s3); // } } } else { String url = null; final String className = referencedClass.qualifiedName(); if (referencedClass.isIncluded()) { url = "#" + className; } else { url = getExternalUrl(className); if (!StringUtils.hasText(url)) { label = className; } } if (referencedMember != null) { if (referencedMember instanceof ExecutableMemberDoc) { if (referencedMemberName.indexOf('(') < 0) { final ExecutableMemberDoc executableDoc = (ExecutableMemberDoc)referencedMember; referencedMemberName = referencedMemberName + executableDoc.signature(); } if (StringUtils.hasText(referencedMemberName)) { label = referencedMemberName; } else { label = seeTagText; } } if (referencedClass.isIncluded()) { url += "." + referencedMemberName; } else if (StringUtils.hasText(url)) { url += "#" + referencedMemberName; } else { label = referencedMember.toString(); } } if (!StringUtils.hasText(label)) { label = referencedClass.name(); } link(writer, url, label, code); } } } } public static void tagWithAnchor(final XmlWriter writer, final QName tag, final String name, final String title) { writer.startTag(tag); writer.attribute(HtmlAttr.CLASS, "title"); writer.startTag(HtmlElem.A); writer.attribute(HtmlAttr.NAME, name); writer.text(title); writer.endTag(HtmlElem.A); writer.endTagLn(tag); } public static void text(final StringBuilder text, final String string) { int index = 0; final int lastIndex = string.length(); String escapeString = null; for (int i = index; i < lastIndex; i++) { final char ch = string.charAt(i); switch (ch) { case '&': escapeString = "&"; break; case '<': escapeString = "<"; break; case '>': escapeString = ">"; break; case 9: case 10: case 13: // Accept these control characters break; default: // Reject all other control characters if (ch < 32) { throw new IllegalStateException( "character " + Integer.toString(ch) + " is not allowed in output"); } break; } if (escapeString != null) { if (i > index) { text.append(string, index, i - index); } text.append(escapeString); escapeString = null; index = i + 1; } } if (lastIndex > index) { text.append(string, index, lastIndex - index); } } public static void title(final XmlWriter writer, final QName element, final String title) { writer.startTag(element); writer.startTag(HtmlElem.SPAN); writer.attribute(HtmlAttr.CLASS, "label label-primary"); writer.text(title); writer.endTag(HtmlElem.SPAN); writer.endTagLn(element); } public static void title(final XmlWriter writer, final String name, final String title) { writer.startTag(HtmlElem.DIV); writer.attribute(HtmlAttr.CLASS, "title"); anchor(writer, name, title); writer.endTagLn(HtmlElem.DIV); } public static void typeName(final XmlWriter writer, final Type type) { String typeName; final String qualifiedTypeName = type.qualifiedTypeName(); if (isTypeIncluded(type) || getExternalUrl(qualifiedTypeName) != null) { typeName = type.typeName(); } else { typeName = qualifiedTypeName; } writer.text(typeName); writer.text(type.dimension()); } public static void typeNameLink(final XmlWriter writer, final Type type) { if (type instanceof WildcardType) { final WildcardType wildCard = (WildcardType)type; writer.text("?"); final Type[] extendsBounds = wildCard.extendsBounds(); if (extendsBounds.length > 0) { writer.text(" extends "); for (int i = 0; i < extendsBounds.length; i++) { if (i > 0) { writer.text(", "); } final Type extendsType = extendsBounds[i]; typeNameLink(writer, extendsType); } } } else { final String qualifiedTypeName = type.qualifiedTypeName(); final String externalLink = getExternalUrl(qualifiedTypeName); final boolean included = isTypeIncluded(type); if (externalLink != null) { HtmlUtil.serializeA(writer, "", externalLink, type.typeName()); } else if (included) { final String url = "#" + qualifiedTypeName; HtmlUtil.serializeA(writer, "", url, type.typeName()); } else { writer.text(qualifiedTypeName); } if (type instanceof ParameterizedType) { final ParameterizedType parameterizedType = (ParameterizedType)type; final Type[] typeArguments = parameterizedType.typeArguments(); if (typeArguments.length > 0) { writer.text("<"); for (int i = 0; i < typeArguments.length; i++) { if (i > 0) { writer.text(", "); } final Type typeParameter = typeArguments[i]; typeNameLink(writer, typeParameter); } writer.text(">"); } } } writer.text(type.dimension()); } public static boolean validOptions(final String options[][], final DocErrorReporter docerrorreporter) { for (final String[] option : options) { final String argName = option[0].toLowerCase(); if (argName.equals("-d")) { final String destDir = option[1]; final File file = new File(destDir); if (!file.exists()) { docerrorreporter.printNotice("Create directory" + destDir); file.mkdirs(); } if (!file.isDirectory()) { docerrorreporter.printError("Destination not a directory" + file.getPath()); return false; } else if (!file.canWrite()) { docerrorreporter.printError("Destination directory not writable " + file.getPath()); return false; } } } return true; } }